﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.AddIn;
using RootfusAddinView;
using ROOTNET.Interface;

namespace GeneralHistogramOperations.TAddAddIn
{
    /// <summary>
    /// An addin that will do division of two histograms.
    /// </summary>
    [AddIn("Add Histograms", Description = "Takes a set of histograms as input and produces a histogram as output possibly tracking the errors")]
    public class TAddAddIn : RootfusSurfaceItem
    {
        /// <summary>
        /// Deafult dtor.
        /// </summary>
        public TAddAddIn()
        {
            ///
            /// Input is a list of histos, output is the added ones all together!
            /// 

            _input_pins.Add(_operands);
            _output_pins.Add(_result);

        }

        public bool CalculateErrors { get; set; }

        public class OurState
        {
            public bool _calc_errors = false;
        }

        private OurState _cached_state = new OurState();

        private void CacheState()
        {
            _cached_state._calc_errors = CalculateErrors;
        }

        private bool StateDifferentFromCache()
        {
            return _cached_state._calc_errors != CalculateErrors;
        }

        /// <summary>
        /// Cache the local copy of the user interface. Best to
        /// reference SurfaceUI property as that will make sure
        /// it is created.
        /// </summary>
        private TAddAddInUINormal _ui_norm = null;

        /// <summary>
        /// Returns the normal UI. Only create one per addin instance! If you get asked
        /// for it multiple times return the same one!
        /// </summary>
        public override System.Windows.FrameworkElement SurfaceUI
        {
            get
            {
                if (_ui_norm == null)
                {
                    _ui_norm = new TAddAddInUINormal();
                }
                return _ui_norm;
            }
        }

        /// <summary>
        /// Return the config UI. Return a new one each time, or keep
        /// track -- whatever is simpler.
        /// </summary>
        public override System.Windows.FrameworkElement ConfigUI
        {
            get
            {
                TAddAddInUIConfig ui = new TAddAddInUIConfig();
                ui.DataContext = this;
                CacheState();
                return ui;
            }
        }

        /// <summary>
        /// The config has closed. See if our options changed. If so, update things!
        /// </summary>
        public override void ConfigDone()
        {
            if (StateDifferentFromCache())
            {
                CacheState();
                Callback.UpdateSaveObject(_cached_state);
                Update();
            }
        }

        /// <summary>
        /// Our settings are getting set, externally.
        /// </summary>
        /// <param name="xml_config"></param>
        public override void SetConfigXML(string xml_config)
        {
            _cached_state = Callback.ConvertXMLToSettings<OurState>(xml_config);
            CalculateErrors = _cached_state._calc_errors;
        }

        /// <summary>
        /// If you don't need a config -- then get rid fo the ConfigUI and change the
        /// return to false.
        /// </summary>
        public override bool HasSettingsUI
        {
            get { return true; }
        }

        /// <summary>
        /// The numerator and denominator pins.
        /// </summary>
        class TROOTHistPinName : PinDefinition
        {
            string _name;
            public TROOTHistPinName(string name)
            {
                _name = name;
            }
            public override string Name
            {
                get { return _name; }
            }

            /// <summary>
            /// We can take a large number of inputs...
            /// </summary>
            public override PinConnectionType ConnectionType
            {
                get
                {
                    return PinConnectionType.PinInfinite;
                }
            }
        }

        private List<PinDefinition> _input_pins = new List<PinDefinition>();
        private TROOTHistPinName _operands = new TROOTHistPinName("Histograms to Add");

        private List<string> _output_pins = new List<string>();
        private string _result = "Result Histogram";

        /// <summary>
        /// Hold onto the result histogram.
        /// </summary>
        private NTH1 _result_hist = null;

        /// <summary>
        /// What are our input pins? Make some custom ones based on
        /// PinDefinition as your parent class. It is normal to create this
        /// list just once.
        /// </summary>
        public override IList<PinDefinition> InputPins
        {
            get { return _input_pins; }
        }

        /// <summary>
        /// What are our output pins? Similar to before. It is normal
        /// to create a list once.
        /// </summary>
        public override IList<string> OutputPinNames
        {
            get { return _output_pins; }
        }

        /// <summary>
        /// Rootfus thinks inputs have changed. Recalc and if things have changed,
        /// send the update down the line.
        /// </summary>
        public override void Update()
        {
            _result_hist = null;

            ///
            /// Get input root objects and convert them to 1D histos
            /// 

            NTObject[] histos = Callback.GetConnectedPinDataAsTObjects(_operands);

            ///
            /// Now -- lets see if we can add them!
            /// 

            foreach (NTH1 hist in histos)
            {
                if (_result_hist == null)
                {
                    _result_hist = hist.Clone() as NTH1;
                    if (CalculateErrors)
                    {
                        _result_hist.Sumw2();
                    }
                }
                else
                {
                    _result_hist.Add(hist);
                }
            }

            ///
            /// Make sure everything down-stream is updated now!
            /// 

            Callback.OutputPinsChanged();
        }

        /// <summary>
        /// Someone want some info from us -- return it!
        /// </summary>
        /// <param name="pin"></param>
        /// <returns></returns>
        public override NTObject GetPinDataAsTObject(string pin)
        {
            if (pin != _result)
            {
                return null;
            }
            return _result_hist;
        }
    }
}
